#pragma once

#include <memory>
#include <string>
#include <unordered_map>

namespace singleton {

    class SingletonFactory {

    public:

        /**
          * @brief  获取单例工厂的指针
          * @note   获取到的工厂全局唯一
          * @retval 单例工厂的指针
          */
        static SingletonFactory *getFactory();

        /**
          * @brief  注册单例到单例工厂
          * @note   None
          * @param  T          函数模板参数，单例类型
          * @param  class_name 单例名称
          * @param  args       单例实例化需要的参数
          * @retval 实例化后的单例指针
          */
        template<typename T, typename... Args>
        T *registeredSingleton(const std::string &class_name, Args &&...args) {
            std::shared_ptr<T> ptr = std::make_shared<T>(std::forward<Args>(args)...);
            singleton_map_.emplace(class_name, ptr);
            return ptr.get();
        }

        /**
          * @brief  根据函数模板参数和单例名称获取单例指针
          * @note   如果没有被注册过则返回空指针
          * @param  T          函数模板参数，单例的类型
          * @param  class_name 单例名称
          * @retval 单例的指针
          */
        template<typename T>
        T *getSingleton(const std::string &class_name) {
            if (singleton_map_.count(class_name) == 0) {
                return nullptr;
            }
            return static_cast<T *>(singleton_map_.at(class_name).get());
        }

        /**
          * @brief  根据单例名称获取单例
          * @note   如果没有被注册过则返回空指针
          * @param  class_name 单例名称
          * @retval void *类型的单例的指针
          */
        void *getSingleton(const std::string &class_name);

        /**
          * @brief  删除注册的单例
          * @param  class_name 单例名称
          */
        void removeSingleton(const std::string &class_name);

    private:

        // 单例对象容器
        std::unordered_map<std::string, std::shared_ptr<void>> singleton_map_;

    };

}
